package com.walter.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.walter.JwtUtil;
import com.walter.common.PageVO;
import com.walter.entity.Menu;
import com.walter.entity.Role;
import com.walter.entity.User;
import com.walter.entity.UserRole;
import com.walter.exception.LogicException;
import com.walter.mapper.*;
import com.walter.model.form.AddUserForm;
import com.walter.model.form.BindRolesForm;
import com.walter.model.form.UpdatePwdForm;
import com.walter.model.query.UserQuery;
import com.walter.model.vo.MenuVO;
import com.walter.model.vo.UserInfoVO;
import com.walter.model.vo.UserVO;
import com.walter.model.vo.UserVODetail;
import com.walter.security.Jwt;
import com.walter.util.Kv;
import com.walter.util.MyCommon;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author ：ch
 * @date ：Created in 2021/5/25
 * @description：
 * @modified By：
 * @version: 1.0
 */
@Service
@Slf4j
public class UserService {
    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private MenuMapper menuMapper;

    @Autowired
    private RoleMenuMapper roleMenuMapper;

    @Autowired
    private UserRoleMapper userRoleMapper;

    @Autowired
    private RoleService roleService;

    @Value("${built-in administrator}")
    private String adminInfo;

    @Autowired
    private JwtUtil jwtUtil;

    @Value("${built-in adminRole}")
    private String adminRole;

    //default user:admin
    @Transactional
    public Boolean initAdmin(){
        String[] arr =  adminInfo.split(ReUtil.escape('|'));// 转义 |    //adminInfo.split("\\|");// 转义 |
        User admin = userMapper.selectOne(new User().setUserName(arr[0]));
        if (null == admin){
            String salt = arr[4];
            String encodePwd = MyCommon.encodePassword(arr[1],salt);
            User user = new User().setUserName(arr[0]).setPassword(encodePwd).setSalt(salt).setNickName(arr[2])
                    .setGender(arr[3]).setSalt(arr[4]).setCreateTime(new Date());
            user.insert();
            userRoleMapper.insert(new UserRole().setUserId(user.getId())
                    .setRoleId(roleService.findByName(adminRole).getId()).setCreateTime(new Date()));
        }
        return true;
    }

    public UserVODetail info(String token){
        // 从token中拿出user信息
        token = token.substring(7);
        String userName = jwtUtil.getUsernameFromToken(token);
        User user = userMapper.selectOne(new User().setUserName(userName));
        UserVODetail retVal = new UserVODetail(user);
        //binding's roles
        List<Role> roleList = roleMapper.findByUserId(user.getId());
        retVal.setRoleList(roleList);
        List<Integer> roleIds = roleList.stream().map(role -> role.getId()).collect(Collectors.toList());
        retVal.setRoleIds(roleIds);
        List<MenuVO> menuVOList = menuMapper.findByUserId(user.getId());
        //need roleBinding's subMenu
        List<Integer> menuIds = roleMenuMapper.findByRoleIds(Kv.by("roleIdList",roleIds));
        List<String> menuPaths = new ArrayList<>(); // 用于前端动态路由
        menuVOList.stream().forEach(menuVO -> {
            menuPaths.add(menuVO.getUrl());
            List<Menu> temp = new ArrayList<>();
            for (Menu menu : menuVO.getSubMenuList()){
                if (menuIds.contains(menu.getId())) {
                    temp.add(menu);
                    menuPaths.add(menu.getUrl());
                }
            }
            menuVO.setSubMenuList(temp);
        });
        return retVal.setMenuVOList(menuVOList).setMenuPaths(menuPaths);
    }

    //add
    public Integer add(AddUserForm form){
        Integer retVal = 0;
        List<User> users = userMapper.selectByMap(Kv.by(User.USER_NAME,form.getUserName()));
        if (CollUtil.isNotEmpty(users)){
            throw new LogicException("用户名不能重复");
        }
        List<User> userList = userMapper.selectByMap(Kv.by(User.NICK_NAME,form.getNickName()));
        if (CollUtil.isNotEmpty(userList)){
            throw new LogicException("昵称不能重复");
        }
        if (StrUtil.isEmpty(form.getPassword()) || StrUtil.isEmpty(form.getConfirmPassword()))
            throw new LogicException("输入的两次密码都不能为空");
        else if (!form.getPassword().equals(form.getConfirmPassword()))
            throw new LogicException("输入的两次密码不一致");
        User user = new User();
        BeanUtil.copyProperties(form,user);
        Date now = new Date();
        String salt = MyCommon.generateSalt();
        String encodePwd = MyCommon.encodePassword(form.getPassword(),salt);
        retVal += userMapper.insert(user.setCreateTime(now).setSalt(salt).setPassword(encodePwd));
        // 绑定角色
        retVal += userRoleMapper.addInBatch(Kv.by("userId",user.getId()).set("createTime",now).set("roleList",form.getRoleIds()));
        return retVal;
    }

    //update 用户名昵称不能重复 todo
    public Boolean update(UserInfoVO form){
        User updatedUser = this.userIsExist(form.getId());
        // todo hardCode
        if (updatedUser.getUserName().equals("admin")) {
            log.info("built-in admin can not update");
            throw new LogicException("内置超级管理员不允许修改");
        }
        BeanUtil.copyProperties(form,updatedUser);
        Date now = new Date();
        userMapper.updateById(updatedUser.setUpdateTime(now));
        // 重绑定角色
        userRoleMapper.deleteByMap(Kv.by(UserRole.USER_ID,form.getId()));
        userRoleMapper.addInBatch(Kv.by("userId",form.getId()).set("createTime",now).set("roleList",form.getRoleIds()));
        return true;
    }

    //find [query condition]todo
    public PageVO<UserVO> find(UserQuery query){
        Page<UserVO> page = new Page<>(query.getPage().getPageNum(),query.getPage().getPageSize());
        List<User> users = userMapper.find(page,BeanUtil.beanToMap(query));
        List<UserVO> records = users.stream().map(UserVO :: new).collect(Collectors.toList());
        return new PageVO<>(page.setRecords(records));
    }

    //findOne
    public UserInfoVO findOne(Integer userId){
        User user = this.userIsExist(userId);
        return new UserInfoVO(user);
    }

    public Boolean updatePwd(UpdatePwdForm form){
        if (!Objects.equals(form.getNewPwd(),form.getRepeatedPwd()))
            throw new LogicException("输入的两次新密码不一致");
        Integer currentId = (Integer) Jwt.currentId();
        User user = this.userIsExist(currentId);
        // todo 内置超级管理员修改密码

        String encodePwd = MyCommon.encodePassword(form.getOriginalPwd(),user.getSalt());
        if (!user.getPassword().equals(encodePwd)){
            throw new LogicException("原密码输入错误");
        }
        String salt = MyCommon.generateSalt();
        encodePwd = MyCommon.encodePassword(form.getNewPwd(),salt);
        return userMapper.updateById(user.setPassword(encodePwd).setLastUpdatePassTime(new Date()).setSalt(salt)) > 0;
    }

    //resetPwd
    public Boolean resetPwd(Integer userId){
        User user = this.userIsExist(userId);
        // todo hardCode
        if (user.getUserName().equals("admin")) {
            log.info("built-in admin can not resetPwd");
            throw new LogicException("内置超级管理员不允许重置密码");
        }
        String salt = MyCommon.generateSalt();
        String encodePwd = MyCommon.encodePassword("123456",salt);//should config todo
        return userMapper.updateById(user.setPassword(encodePwd).setLastUpdatePassTime(new Date()).setSalt(salt)) > 0;
    }

    private User userIsExist(Integer userId){
        if (null == userId){
            throw new LogicException("用户id为空");
        }
        User user = userMapper.selectById(userId);
        if (null == user){
            throw new LogicException("id为" + userId + "的用户不存在");
        }
        return user;
    }

    public Integer toggleIsEnabled(Integer userId){
        return userMapper.updateForSet(" is_enabled = if('yes' = is_enabled,'no','yes')",
                new EntityWrapper<User>().eq(User.ID,userId));
    }

    //bind roles
    public Integer bindRoles(BindRolesForm form){
        Integer retVal = 0;
        List<Integer> roleIdList = form.getRoleIdList();
        userRoleMapper.deleteByMap(Kv.by(UserRole.USER_ID,form.getUserId()));
        retVal += userRoleMapper.addInBatch(Kv.by("roleList",roleIdList).set("userId",form.getUserId()).set("createTime",new Date()));
        return retVal;
    }
}
